package websocket

import (
	"github.com/gorilla/websocket"
	"github.com/star-find-cloud/star-chat/conf"
	log "github.com/star-find-cloud/star-chat/pkg/logger"
	"net/http"
	"time"
)

func initConf() *websocket.Upgrader {
	c := conf.GetConfig()
	return &websocket.Upgrader{
		ReadBufferSize:    c.WebSocket.ReadBufferSize,
		WriteBufferSize:   c.WebSocket.WriteBufferSize,
		EnableCompression: c.WebSocket.EnableCompression,
		CheckOrigin: func(r *http.Request) bool {
			return r.Header.Get("Origin") == c.WebSocket.Origin
		},
	}
}

func (c *Connect) readMessage() {
	defer c.Close()
	for {
		if c.isClosed {
			return
		}

		// 读取消息
		wsMsgType, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err,
				websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.HttpLogger.Errorf("Read message error: %v", err)
			}
			return
		}

		// 拼接消息
		msg := &Message{
			WebSocketType: wsMsgType,
			Data:          message,
			Time:          time.Now(),
		}

		// 获取消息类型
		msgType, err := c.GetMessageType(msg.Data)
		if err != nil {
			log.HttpLogger.Errorf("Get message type error: %v", err)
			return
		}

		// 判断消息类型是否为 webRTC 信令消息
		if msg.WebSocketType == 1 {
			switch msgType {
			case string(MessageTypeNormal):
				msg.MessageType = MessageTypeNormal
			case string(MessageTypeAnswer):
				msg.MessageType = MessageTypeAnswer
			case string(MessageTypeICE):
				msg.MessageType = MessageTypeICE
			case string(MessageTypeOffer):
				msg.MessageType = MessageTypeOffer
			}
		}

		select {
		// 将消息发送到业务层通道（需业务层提前注册回调）
		case c.BusinessChan <- msg:
		case <-c.Stop:
			return
		case <-time.After(25 * time.Second):
			log.HttpLogger.Warnf("BusinessChan send message timeout")
		}
	}
}

func (c *Connect) writeMessage() {
	defer c.Close()
	for {
		select {
		case message, ok := <-c.Send:
			if !ok {
				// 通道关闭, 退出连接
				return
			}

			c.mu.Lock()
			if c.isClosed {
				c.mu.Unlock()
				return
			}
			err := c.Conn.WriteMessage(message.WebSocketType, message.Data)
			c.mu.Unlock()
			if err != nil {
				return
			}
		case <-c.Stop:
			return
		}
	}
}

func (c *Connect) Close() {
	c.once.Do(func() {

		close(c.Stop)
		close(c.Send)
		close(c.BusinessChan)
		if c.Conn != nil {
			c.Conn.Close()
		}
	})
}

// startPing 心跳监测
func (c *Connect) startPing() {
	ticker := time.NewTicker(30 * time.Second) // 每30秒检查一次心跳
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			c.mu.Lock()
			if !c.isClosed {
				err := c.Conn.WriteMessage(websocket.PingMessage, nil)
				if err != nil {
					log.HttpLogger.Errorf("Send ping message failed: %v", err)
					c.mu.Unlock()
					c.Close()
					return
				}
			}
			c.mu.Unlock()
		case <-c.Stop:
			return
		}
	}
}

func GetConnect(w http.ResponseWriter, r *http.Request) *Connect {
	upgrader := initConf()
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.HttpLogger.Errorf("webSocket connet failed, ERROR: %v", err)
		return nil
	}

	// 设置消息大小限制和心跳
	conn.SetReadLimit(1 << 20)
	conn.SetReadDeadline(time.Now().Add(60 * time.Second))
	conn.SetPongHandler(func(string) error {
		conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		return nil
	})

	c := &Connect{
		Conn:         conn,
		Send:         make(chan *Message, 1024),
		Stop:         make(chan struct{}),
		BusinessChan: make(chan *Message, 1024),
	}
	go c.readMessage()
	go c.writeMessage()
	go c.startPing()

	return c
}
